package com.example.model;

import com.alibaba.fastjson.JSONObject;
import com.example.annotations.Param;
import com.example.annotations.UploadFile;
import com.example.auth.uitls.UserModelUtils;
import com.example.handler.HttpHandler;
import com.example.handler.LoginHandler;
import com.example.model.log.service.LogHandler;
import com.example.model.log.service.LogModelService;
import com.example.utils.ObjectMaps;
import com.example.utils.ObjectTypeUtils;
import com.example.utils.PathUtils;
import com.example.utils.StringUtils;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.RequestBody;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.multipart.MultipartForm;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Classname HttpBody
 * @Description TODO
 * @Date 2022/5/24 17:15
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class HttpBody extends AbstractVerticle {


  private HttpHandler httpHandler;

  private LogHandler logHandler;

  public Handler<RoutingContext>body(Method method, Object obj, Class<?>[] clazzs){
    return routingContext -> {
      Object objStr=null;
      try {
        List<FileUpload> uploads = routingContext.fileUploads();
        List<UploadModel> uploadModels=null;
        if(uploads!=null && uploads.size() > 0){
            uploadModels=new ArrayList<>();
           UploadFile uploadFile=method.getAnnotation(UploadFile.class);
           if(uploadFile != null){
               Vertx vertx=(Vertx)ObjectMaps.getObjectByClass(Vertx.class);
               String path=uploadFile.path();
               if("".equals(path)){
                   path= PathUtils.getPath();
               }
               for (FileUpload file : uploads) {
                   path=path+ File.separator +file.fileName();
                   File fileObj=new File(path);
                   if(fileObj.exists()){
                       if(uploadFile.isOnly()){
                           forceDelete(fileObj);
                       }else {
                           path=path+System.currentTimeMillis();
                           fileObj=new File(path);
                       }
                   }
                   UploadModel uploadModel=new UploadModel();
                   uploadModel.setFileName(fileObj.getName());
                   uploadModel.setPath(fileObj.getPath());
                   uploadModel.setContentType(file.contentType());
                   uploadModel.setFileSize(file.size());
                   uploadModels.add(uploadModel);
                   vertx.fileSystem().move(file.uploadedFileName(),  path, res->{
                       if(res.succeeded()) {
                           System.out.println("upload success.");
                       } else {
                           res.cause().printStackTrace();
                       }
                   });

               }
           }
        }
        List<Object> objList=new ArrayList<Object>();
        MultiMap multiMap=routingContext.queryParams();

        MultipartForm multipartForm = MultipartForm.create();
        MultiMap attributes = routingContext.request()
          .formAttributes();

        attributes.forEach(attribute -> {
            multipartForm.attribute(attribute.getKey(), attribute.getValue());
        });


       if(clazzs.length>0){
             for (int i = 0; i < clazzs.length; i++) {
               Class<?> cls=clazzs[i];
               Annotation[][] annotations= method.getParameterAnnotations();
               Annotation[] an=annotations[i];
               if(cls.getName().equals(HttpServerResponse.class.getName())){
                    objList.add(routingContext.response());
               }else if(cls.getName().equals(HttpServerRequest.class.getName())) {
                   HttpServerRequest request = routingContext.request();
                   objList.add(request);
               }else if (an.length>0) {
                    //处理注解
                    dealAnnationParamHandler(objList,an,cls,routingContext,multiMap);
               }else if(cls.getName().equals(UploadBody.class.getName())){
                   UploadBody uploadBody=new UploadBody();
                   uploadBody.setUploadModels(uploadModels);
                   objList.add(uploadBody);
               } else {
                  objList.add(null);
               }
             }
             if(httpHandler==null){
                Object httpHandlerObj= ObjectMaps.getObjectByClass(HttpHandler.class);
                if(httpHandlerObj != null){
                    httpHandler=(HttpHandler)httpHandlerObj;
                }
             }
             if(httpHandler!=null){
                httpHandler.bedoreHandler(objList.toArray());
             }
              objStr=method.invoke(obj,objList.toArray());
               if(logHandler==null){
                   Object handler=ObjectMaps.getObjectByClass(LogHandler.class);
                   if(handler != null){
                       logHandler=(LogHandler) handler;
                   }
               }
                if (logHandler != null) {
                    HttpServerResponse response=null;
                    if(objStr!=null){
                        response=routingContext.response();
                    }
                    HttpServerRequest request=routingContext.request();
                    logHandler.LogHandler(request,response,objList,objStr);
                }

             if(httpHandler!=null){
                 Object value=httpHandler.afterHandler(objList.toArray(),objStr);
                 if(value != null){
                    objStr=value;
                 }
             }
       }else {
          objStr=method.invoke(obj);
           if(logHandler==null){
               Object handler=ObjectMaps.getObjectByClass(LogHandler.class);
               if(handler != null){
                   logHandler=(LogHandler) handler;
               }
           }
           if (logHandler != null) {
               HttpServerResponse response=null;
               if(objStr!=null){
                   response=routingContext.response();
               }
               HttpServerRequest request=routingContext.request();
               logHandler.LogHandler(request,response,null,objStr);
           }

       }
      }catch (Exception e) {
        e.printStackTrace();
      }
      if(objStr!=null){
          routingContext.response().putHeader("content-type", "application/json; charset=utf-8")
                  .end(JSONObject.toJSONString(objStr));
      }

      //移除登录会话
      removeSession();
    };
  }



  //处理注解
  private void dealAnnationParamHandler(List<Object> objList, Annotation[] an,Class<?> cls,RoutingContext routingContext,MultiMap multiMap){
        Param param = paramFieldHandler(an);
        com.example.annotations.RequestBody requestBody=requestBodyHandler(an);
          if (multiMap == null) {
                routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end("参数不得为空");
          }
          if(param!=null){
            if (multiMap != null) {
                //默认值
              String defaultValue=param.defalultValue();
              Object value = multiMap.get(param.value());
              //value非空并且开启了 required注解
              if (StringUtils.isEmpty(value) ) {
                  RequestBody req=routingContext.body();
                  JsonObject var=req.asJsonObject();

                  if(var!=null && ! var.isEmpty()){
                      Map o=var.getMap();
                      Object v=o.get(param.value());
                      //获取到的值为空，赋值默认值
                      if(v==null && !"".equals(defaultValue)){
                          v=defaultValue;
                      }
                      if(v==null && param.required()){
                          routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end(param.value() + "不得为空");
                          return;
                      }
                      paramTypeChange(v,cls,objList);
                  }else {
                      if(value==null && !"".equals(defaultValue)){
                          value=defaultValue;
                          paramTypeChange(value,cls,objList);
                      }else if(param.required()) {
                          routingContext.response().putHeader("content-type", "application/json; charset=utf-8").end(param.value() + "不得为空");
                          return;
                      }else {
                          objList.add(null);
                      }
                  }
              }else if( !param.required() && StringUtils.isEmpty(value)){
                  //获取到的值为空，赋值默认值
                  objList.add(null);
              }else  {
                //参数类型处理
                  paramTypeChange(value,cls,objList);
              }
            }
          }
          //处理requestBody
          if(requestBody!=null){
              RequestBody req=routingContext.body();
              JsonObject var=req.asJsonObject();
              if(var!=null && ! var.isEmpty()){
                  Map o=var.getMap();
                 Object data=JSONObject.parseObject(JSONObject.toJSONString(o),cls);
                  objList.add(data);
              }else {
                  objList.add(null);
              }
          }

  }

  private Param paramFieldHandler(Annotation[] annotations){
      for (int i = 0; i < annotations.length; i++) {
          Annotation annotation = annotations[i];
          if(annotation instanceof Param){
              Param param = (Param) annotation;
              return param;
          }
      }
      return null;
  }

  //参数类型改变
  private void paramTypeChange(Object obj,Class<?> cls,List<Object> objectList){
      if(obj==null){
          objectList.add(null);
      }else if("java.lang.Integer".equals(cls.getName())){
          Integer value= ObjectTypeUtils.getInteger(String.valueOf(obj));
          objectList.add(value);
      }else if ("java.lang.Double".equals(cls.getName())) {
            Double value = ObjectTypeUtils.getDouble(String.valueOf(obj));
            objectList.add(value);
      }else if("java.lang.Float".equals(cls.getName())){
            Float value = ObjectTypeUtils.getFloat(String.valueOf(obj));
            objectList.add(value);
      }else if("java.util.Date".equals(cls.getName())){
          Date date = ObjectTypeUtils.getDate(String.valueOf(obj));
          objectList.add(date);
      }else  {
          String str=JSONObject.toJSONString(obj);
          Object v=JSONObject.parseObject(str,cls);
          objectList.add(v);
      }
  }

  private com.example.annotations.RequestBody requestBodyHandler(Annotation[] annotations){
      for (int i = 0; i < annotations.length; i++) {
        Annotation annotation = annotations[i];
        if(annotation instanceof com.example.annotations.RequestBody){
            com.example.annotations.RequestBody requestBody = (com.example.annotations.RequestBody) annotation;
          return requestBody;
        }
      }
      return null;
  }

    private static void removeSession(){
        try {
            UserModelUtils.remove();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean forceDelete(File file) {
        boolean result = file.delete();
        int tryCount = 0;
        while (!result && tryCount++ < 10) {
            System.gc();    //回收资源
            result = file.delete();
        }
        return result;
    }

}
